﻿using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Web.Configuration;

using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Search.Administration;

using Kiiro.Common.Entities;
using Kiiro.Common.Utility;
using Kiiro.Logging;
using Kiiro.Model.Utility;
using Kiiro.ExceptionManagement;

using AppName = Kiiro.Common.Utility.Constants.AppName;
using Permissions = Kiiro.Common.Utility.Constants.Permissions;
using SPSiteDefinition = Kiiro.Common.Utility.Constants.SPSiteDefinition;
using CustomListInfo = Kiiro.Common.Utility.Constants.SPSiteDefinition.CustomListInfo;
using SecurityConstants = Kiiro.Common.Utility.Constants.Security;

namespace Kiiro.Model.EventHandlers
{
    public class KiiroProject : SPFeatureReceiver
    {
        private const string SPGroupDescription = Constants.SPSiteDefinition.SPGroupDescription;

        public override void FeatureActivated ( SPFeatureReceiverProperties properties )
        {
            LoggingManager.LogMessage ( "TRACE", "Kiiro.Project FeatureActivated Begin" );

            try
            {
                SPWeb web = properties.Feature.Parent as SPWeb;

                Guid siteCollectionId = web.Site.ID;
                string serverRelativeUrl = web.ServerRelativeUrl;

                web.AllowUnsafeUpdates = true;

                //needed when remove the recent discussions page
                if (web.GetFile("RecentDiscussions.aspx").Exists)
                    web.Files["RecentDiscussions.aspx"].Delete();

                KiiroSolutionControllerHelpers.EnsureSiteEvents ( siteCollectionId );
                KiiroSolutionControllerHelpers.EnsureSiteFeatures ( siteCollectionId, serverRelativeUrl );
                KiiroSolutionControllerHelpers.EnsureWebEvents ( siteCollectionId, serverRelativeUrl );
                KiiroSolutionControllerHelpers.EnsureWebFeaturesProject ( siteCollectionId, serverRelativeUrl );

                if ( web.Lists.Cast<SPList> ( ).Count ( list => list.Title == "Activity History" ) == 0 )
                    web.Lists.Add ( "Activity History", "Kiiro Activity History List", "Lists/ActivityHistory", "2506CDB8-FB9D-4d96-A81E-5BEC418EE1C7", 50000, "" );
                if ( web.Lists.Cast<SPList> ( ).Count ( list => list.Title == "Discussions" ) == 0 )
                    web.Lists.Add ( "Discussions", "Kiiro Discussions List", "Lists/Discussions", "2506CDB8-FB9D-4d96-A81E-5BEC418EE1C7", 50001, "" );
                if ( web.Lists.Cast<SPList> ( ).Count ( list => list.Title == "Documents" ) == 0 )
                    web.Lists.Add ( "Documents", "Kiiro Documents List", "Documents", "2506CDB8-FB9D-4d96-A81E-5BEC418EE1C7", 50002, "" );
                if ( web.Lists.Cast<SPList> ( ).Count ( list => list.Title == "Team" ) == 0 )
                    web.Lists.Add ( "Team", "Kiiro Team List", "Lists/Team", "2506CDB8-FB9D-4d96-A81E-5BEC418EE1C7", 50006, "" );
                if ( web.Lists.Cast<SPList> ( ).Count ( list => list.Title == "Work" ) == 0 )
                    web.Lists.Add ( "Work", "Kiiro Work List", "Lists/Work", "2506CDB8-FB9D-4d96-A81E-5BEC418EE1C7", 50007, "" );
                
                if ( web.Lists.Cast<SPList> ( ).Count ( list => list.Title == "Kiiro Main Navigation" ) == 0 )
                {
                    web.Lists.Add ( "Kiiro Main Navigation", "Kiiro Main Navigation List", "Lists/MainNavigation", "2506CDB8-FB9D-4d96-A81E-5BEC418EE1C7", 50100, "" );
                    SPList list = web.Lists [ Constants.SPListNames.MainNavigation ];

                    // don't need this field because the list is project level and items in the list are specific to this project
                    list.Fields.Delete ( Constants.NavigationFieldNames.SiteLevel );
                    list.Update ( );
                }
                if ( web.Lists.Cast<SPList> ( ).Count ( list => list.Title == "Kiiro Sub Navigation" ) == 0 )
                {
                    web.Lists.Add ( "Kiiro Sub Navigation", "Kiiro Sub Navigation List", "Lists/SubNavigation", "2506CDB8-FB9D-4d96-A81E-5BEC418EE1C7", 50101, "" );
                    SPList list = web.Lists [ Constants.SPListNames.SubNavigation ];

                    // don't need this field because the list is project level and items in the list are specific to this project
                    list.Fields.Delete ( Constants.NavigationFieldNames.SiteLevel ); 
                    list.Update ( );
                }

                SPList documents = web.Lists [ Constants.SPListNames.Documents ];
                if ( documents != null )
                {
                    documents.EnableVersioning = true;
                    documents.Update ( );
                }

                // Lists must be created before calling EnsureListEventHandlers and EnsureTimerJobs 
                KiiroSolutionControllerHelpers.EnsureListEventHandlers ( siteCollectionId, serverRelativeUrl );
                KiiroSolutionControllerHelpers.EnsureTimerJobs ( siteCollectionId );

                if ( string.IsNullOrEmpty ( web.Properties [ "IsProvisioned" ] ) )
                {
                    LoggingManager.LogMessage ( "TRACE", "Provisioning Project Groups Begin" );
                    SetupSiteGroups ( web );
                    LoggingManager.LogMessage ( "TRACE", "Provisioning Project Groups End" );

                    LoggingManager.LogMessage ( "TRACE", "Provisioning Project Custom Lists Begin" );
                    ProvisionCustomLists ( siteCollectionId, serverRelativeUrl );
                    LoggingManager.LogMessage ( "TRACE", "Provisioning Project Custom Lists End" );

                    web.Properties [ "IsProvisioned" ] = bool.TrueString;
                    web.Properties.Update ( );
                    web.Update ( );
                }

                EnsureRequiredSPGroupMembers ( web );

                web.AllowAutomaticASPXPageIndexing = true;
                web.ASPXPageIndexMode = WebASPXPageIndexMode.Always;
                web.NoCrawl = false;
                web.PresenceEnabled = false;
                web.Navigation.UseShared = false;
                web.QuickLaunchEnabled = false;
                web.Update ( );
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }

            LoggingManager.LogMessage ( "TRACE", "Kiiro.Project FeatureActivated End" );
        }


        private static void SetupSiteGroups ( SPWeb web )
        {
            try
            {
                web.BreakRoleInheritance ( true );
                web.RoleDefinitions.BreakInheritance ( true, true );
                web.AssociatedGroups.Clear ( );
                web.Update ( );

                InheritPortalOwnerGroup ( web );
                SetupOwnersGroup ( web );
                SetupMembersGroup ( web );
                SetupVisitorsGroup ( web );
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }
        }

        private static void SetupOwnersGroup ( SPWeb web )
        {
            try
            {
                string name = string.Format ( "{0} Owners - {1}", AppName.Proper, web.Title );
                int count = web.SiteGroups.Cast<SPGroup> ( ).Count ( x => x.Name.Contains ( name ) );
                name = count > 0 ? string.Format ( "{0}({1})", name, count ) : name;

                web.SiteGroups.Add ( name, web.Author, web.Author, string.Format ( SPGroupDescription, "Full Control", web.Title ) );
                SPGroup owners = web.SiteGroups [ name ];
                owners.Owner = web.ParentWeb.AssociatedOwnerGroup;
                owners.Update ( );

                web.AssociatedOwnerGroup = owners;

                SPRoleDefinition roleDefinition = web.RoleDefinitions.Cast<SPRoleDefinition> ( )
                    .Where ( role => role.Name == "Full Control" )
                    .First ( );

                SPRoleAssignment roleAssignment = new SPRoleAssignment ( owners as SPPrincipal );
                roleAssignment.RoleDefinitionBindings.Add ( roleDefinition );
                web.RoleAssignments.Add ( roleAssignment );

                web.Update ( );
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }
        }

        private static void SetupMembersGroup ( SPWeb web )
        {
            try
            {
                string name = string.Format ( "{0} Members - {1}", AppName.Proper, web.Title );
                int count = web.SiteGroups.Cast<SPGroup> ( ).Count ( x => x.Name.Contains ( name ) );
                name = count > 0 ? string.Format ( "{0}({1})", name, count ) : name;

                web.SiteGroups.Add ( name, web.Author, web.Author, string.Format ( SPGroupDescription, "Contribute", web.Title ) );
                SPGroup members = web.SiteGroups [ name ];
                members.Owner = web.AssociatedOwnerGroup.Owner;
                members.Update ( );

                web.AssociatedMemberGroup = members;

                SPRoleDefinition roleDefinition = web.RoleDefinitions.Cast<SPRoleDefinition> ( )
                    .Where ( role => role.Name == "Contribute" )
                    .First ( );

                SPRoleAssignment roleAssignment = new SPRoleAssignment ( members as SPPrincipal );
                roleAssignment.RoleDefinitionBindings.Add ( roleDefinition );
                web.RoleAssignments.Add ( roleAssignment );

                web.Update ( );
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }
        }

        private static void SetupVisitorsGroup ( SPWeb web )
        {
            try
            {
                string name = string.Format ( "{0} Visitors - {1}", AppName.Proper, web.Title );
                int count = web.SiteGroups.Cast<SPGroup> ( ).Count ( x => x.Name.Contains ( name ) );
                name = count > 0 ? string.Format ( "{0}({1})", name, count ) : name;

                web.SiteGroups.Add ( name, web.Author, web.Author, string.Format ( SPGroupDescription, "Read", web.Title ) );
                SPGroup visitors = web.SiteGroups [ name ];
                visitors.Owner = web.AssociatedOwnerGroup.Owner;
                visitors.Update ( );

                web.AssociatedVisitorGroup = visitors;

                SPRoleDefinition roleDefinition = web.RoleDefinitions.Cast<SPRoleDefinition> ( )
                    .Where ( role => role.Name == "Read" )
                    .First ( );

                SPRoleAssignment roleAssignment = new SPRoleAssignment ( visitors as SPPrincipal );
                roleAssignment.RoleDefinitionBindings.Add ( roleDefinition );
                web.RoleAssignments.Add ( roleAssignment );

                web.Update ( );
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }
        }

        private static void InheritPortalOwnerGroup ( SPWeb web )
        {
            try
            {
                SPGroup owners = web.ParentWeb.AssociatedOwnerGroup;
                //owners.Owner = web.ParentWeb.AssociatedOwnerGroup;
                //owners.Update ( );

                web.AssociatedGroups.Add ( owners );

                SPRoleDefinition roleDefinition = web.RoleDefinitions.Cast<SPRoleDefinition> ( )
                    .Where ( role => role.Name == "Full Control" )
                    .First ( );

                SPRoleAssignment roleAssignment = new SPRoleAssignment ( owners as SPPrincipal );
                roleAssignment.RoleDefinitionBindings.Add ( roleDefinition );
                web.RoleAssignments.Add ( roleAssignment );

                web.Update ( );
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }
        }


        private static void ProvisionCustomLists ( Guid siteCollectionId, string serverRelativeUrl )
        {
            SPContentType baseCustomContentType = null;
            List<SPContentType> customContentTypes = new List<SPContentType> ( );

            using ( SPSite site = new SPSite ( siteCollectionId ) )
            {
                baseCustomContentType = site.RootWeb.ContentTypes [ new SPContentTypeId ( CustomListInfo.BaseCustomItemContentTypeId ) ];
            }

            if ( baseCustomContentType != null )
            {
                using ( SPWeb web = SPHelpers.GetSystemWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    using ( SPWeb portalWeb = web.ParentWeb )
                    {
                        foreach ( SPContentType contentType in portalWeb.ContentTypes )
                        {
                            if ( contentType.Id.IsChildOf ( baseCustomContentType.Id ) && !contentType.Id.Equals ( baseCustomContentType.Id ) )
                            {
                                customContentTypes.Add ( contentType );
                            }
                        }
                    }

                    try
                    {
                        web.AllowUnsafeUpdates = true;

                        foreach ( SPContentType customContentType in customContentTypes )
                        {
                            string title = String.Format ( CustomListInfo.Title, customContentType.Name );
                            string description = String.Format ( CustomListInfo.Description, customContentType.Name );
                            string url = String.Format ( CustomListInfo.Url, title.Replace ( " ", "" ) );
                            string featureId = CustomListInfo.CustomListFeatureId;

                            if ( web.Lists.Cast<SPList> ( ).Count ( list => list.Title == title ) == 0 )
                            {
                                Guid listGuid = web.Lists.Add ( title, description, url, featureId, 50008, "100", SPListTemplate.QuickLaunchOptions.Off );
                                SPList list = web.Lists [ listGuid ];

                                if ( list != null )
                                {
                                    list.ContentTypes.Add ( customContentType );
                                    foreach ( SPContentType contentType in list.ContentTypes )
                                    {
                                        if ( !contentType.Id.Equals ( customContentType.Id ) )
                                            list.ContentTypes.Delete ( contentType.Id );
                                    }

                                    list.Update ( );
                                }
                            }
                        }
                    }
                    catch ( Exception ex ) { ExceptionManager.HandleException ( ex, true ); }
                    finally
                    {
                        web.AllowUnsafeUpdates = false;
                    }
                }
            }
        }

        public void EnsureRequiredSPGroupMembers ( SPWeb web )
        {
            try
            {
                string login = Constants.Security.AD_AUTH_USERS_DOMAIN_GROUP_NAME;
                SPUser allAuthenticated = web.EnsureUser ( login );

                if ( web.AssociatedVisitorGroup.Users.Cast<SPUser> ( ).Count ( x => x.LoginName == login ) > 0 )
                    web.AssociatedVisitorGroup.RemoveUser ( allAuthenticated );

                SPSearchService searchService = SPFarm.Local.Services.GetValue<SPSearchService> ( "SPSearch" );
                login = ( ( SPWindowsService ) searchService ).ProcessIdentity.Username;
                SPUser search = web.EnsureUser ( login );
                if ( web.AssociatedMemberGroup.Users.Cast<SPUser> ( ).Count ( x => x.LoginName == login ) == 0 )
                    web.AssociatedMemberGroup.AddUser ( search );
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }
        }


        public override void FeatureDeactivating ( SPFeatureReceiverProperties properties ) { }

        public override void FeatureInstalled ( SPFeatureReceiverProperties properties ) { }

        public override void FeatureUninstalling ( SPFeatureReceiverProperties properties ) { }
    }
}
